package cc.denglu.sdk;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import org.json.JSONArray;
import org.json.JSONObject;
import org.json.JSONTokener;

/**
 * 目的：把基础方法用protected的形式封装在base里，不直接展现给最终用户
 * 
 * @author cc@denglu.cc songjw@denglu.cc
 * @version 1.0
 * @updated 09-八月-2011 14:59:44
 */
public class Denglu {

	protected String appID;
	protected String apiKey;

	/**
	 * denglu API的域名，默认http://open.denglu.cc 设置此属性以满足以后有做二级域名重定向需求的客户
	 */
	private static String DENGLU_URL = "http://open.denglu.cc";
	/**
	 * DENGLU RESTful API的地址
	 */
	private static HashMap<String, String> apiPath;
	static {
		apiPath = new HashMap<String, String>();
		apiPath.put("user_info", DENGLU_URL + "/api/v3/user_info");
		apiPath.put("get_media", DENGLU_URL + "/api/v3/get_media");
		apiPath.put("bind", DENGLU_URL + "/api/v3/bind");
		apiPath.put("unbind", DENGLU_URL + "/api/v3/unbind");
		apiPath.put("all_unbind", DENGLU_URL + "/api/v3/all_unbind");
		apiPath.put("send_login_feed", DENGLU_URL + "/api/v3/send_login_feed");
		apiPath.put("share", DENGLU_URL + "/api/v3/share");
	}

	/**
	 * 此sdk的版本号，初始为1.0
	 */
	public static final float version = 1.0f;

	/**
	 * 加密方法
	 */
	private String signatureMethod = "MD5";

	@Override
	public void finalize() throws Throwable {

	}

	/**
	 * 构造函数
	 * @param appID	灯鹭后台分配的appID {@link http://open.denglu.cc}
	 * @param apiKey	灯鹭后台分配的apiKey {@link http://open.denglu.cc}
	 * @param signatureMethod	签名算法，暂时只支持MD5
	 * @throws DengluException
	 */
	public Denglu(String appID, String apiKey, String signatureMethod) throws DengluException {
		if (null == appID || "".equals(appID)) {
			throw new DengluException("appid不能为空");
		}

		if (null == apiKey || "".equals(apiKey)) {
			throw new DengluException("apikey不能为空");
		}

		if (signatureMethod != null && !"MD5".equalsIgnoreCase(signatureMethod)) {
			throw new DengluException("只支持MD5加密");
		}

		this.appID = appID;
		this.apiKey = apiKey;
		if (null != signatureMethod) {
			this.signatureMethod = signatureMethod;
		}
	}

	/**
	 * 获取登陆/绑定链接
	 * 
	 * @param isBind
	 *            是否用于绑定（非绑定则为登录）
	 * @param Provider
	 *            通过Denglu.Provider p = Denglu.Provider.guess(mediaNameEn) 获取。
	 *            mediaNameEn获取媒体列表中得到
	 * @param uid
	 *            用户网站的用户ID，绑定时需要
	 * @throws DengluException
	 */
	public String getAuthUrl(Boolean isBind, Provider provider, String uid) throws DengluException {
		if (null != isBind && isBind && null == uid) {
			throw new DengluException("绑定时，需要传送用户ID");
		}
		return null == isBind || !isBind ? provider.getAuthLoginUrl() + "?appid=" + appID : provider.getAuthBindUrl() + "?appid=" + appID + "&uid=" + uid;
	}

	/**
	 * 根据token获取用户信息
	 * 
	 * @param token
	 * @throws DengluException
	 * @return 返回值 eg:
	 *	{
	 * 		"mediaID":7, // 媒体ID
	 *		"createTime":"2011-05-20 16:44:19", // 创建时间
	 *		"friendsCount":0, // 好友数
	 *		"location":null, // 地址
	 *		"favouritesCount":0, // 收藏数
	 *		"screenName":"denglu", // 显示姓名
	 *		"profileImageUrl":"http://head.xiaonei.com/photos/0/0/men_main.gif", // 个人头像
	 *		"mediaUserID":61, // 用户ID
	 *		"url":null, // 用户博客/主页地址
	 *		"city":null, // 城市
	 *		"description":null, // 个人描述
	 *		"createdAt":"", // 在媒体上的创建时间
	 *		"verified":0, // 认证标志
	 *      "name":null, // 友好显示名称
	 *      "domain":null, // 用户个性化URL
	 *      "province":null, // 省份
	 *      "followersCount":0, // 粉丝数
	 *      "gender":1, // 性别 1--男，0--女,2--未知
	 *      "statusesCount":0, // 微博/日记数
	 *      "personID":120 // 个人ID
	 *	}
	 */
	public JSONObject getUserInfoByToken(String token) throws DengluException {
		Request request = new Request(Verb.GET, getApiPath("user_info"));
		request.addQuerystringParameter("token", token);
		this.signRequest(request);
		String result = this.makeRequest(request);
		return (JSONObject) this.parseJson(result);
	}

	/**
	 * 获取当前应用ID绑定的所有社会化媒体及其属性
	 * 
	 * @param appID
	 *            灯鹭应用ID
	 * @throws DengluException
	 * @return 返回值 eg:
	 * [
	 * 	{
	 * 		"mediaID":7, // ID
	 * 		"mediaIconImageGif": "http://test.denglu.cc/images/denglu_second_icon_7.gif", //社会化媒体亮色Icon
	 * 		"mediaIconImage": "http://test.denglu.cc/images/denglu_second_icon_7.png", // 社会化媒体亮色Icon
	 * 		"mediaNameEn":"renren", // 社会化媒体的名称的拼音
	 *		"mediaIconNoImageGif" :"http://test.denglu.cc/images/denglu_second_icon_no_7.gif", // 社会化媒体灰色Icon
	 *		"mediaIconNoImage": "http://test.denglu.cc/images/denglu_second_icon_no_7.png", // 社会化媒体灰色Icon
	 *		"mediaName":"人人网", // 社会化媒体的名称
	 *		"mediaImage":"http://test.denglu.cc/images/denglu_second_7.png" , // 社会化媒体大图标
	 *		"shareFlag":0, // 是否有分享功能 0是1否
	 *		"apiKey":"704779c3dd474a44b612199e438ba8e2" // 社会化媒体的应用apikey
	 *	}
	 *]
	 */
	public JSONArray getMedia() throws DengluException {
		Request request = new Request(Verb.GET, getApiPath("get_media"));
		request.addQuerystringParameter("appid", appID);
		this.signRequest(request);
		String result = this.makeRequest(request);
		return (JSONArray) this.parseJson(result);
	}

	/**
	 * 用户绑定多个社会化媒体账号到已有账号上
	 * 
	 * @param mediaUID
	 *            社会化媒体的用户ID
	 * @param uid
	 *            用户网站那边的用户ID
	 * @param uname
	 *            用户网站的昵称
	 * @param uemail
	 *            用户网站的邮箱
	 * @throws DengluException
	 * @return 返回值 eg: {"result": "1"}
	 */
	public JSONObject bind(String mediaUID, String uid, String uname, String uemail) throws DengluException {
		Request request = new Request(Verb.GET, getApiPath("bind"));
		request.addQuerystringParameter("appid", appID);
		request.addQuerystringParameter("muid", mediaUID);
		request.addQuerystringParameter("uid", uid);
		request.addQuerystringParameter("uname", uname);
		request.addQuerystringParameter("uemail", uemail);
		this.signRequest(request);
		String result = this.makeRequest(request);
		return (JSONObject) this.parseJson(result);
	}

	/**
	 * 用户解除绑定社会化媒体账号
	 * 
	 * @param mediaUID
	 *            社会化媒体的用户ID
	 * @throws DengluException
	 * @return 返回值 eg: {"result": "1"}
	 */
	public JSONObject unbind(String mediaUID) throws DengluException {
		Request request = new Request(Verb.GET, getApiPath("unbind"));
		request.addQuerystringParameter("appid", appID);
		request.addQuerystringParameter("muid", mediaUID);
		this.signRequest(request);
		String result = this.makeRequest(request);
		return (JSONObject) this.parseJson(result);
	}

	/**
	 * 用户解除所有绑定的社会化媒体账号
	 * 
	 * @param uid
	 *            网站的用户ID
	 * @throws DengluException
	 * @return 返回值 eg: {"result": "1"}
	 */
	public JSONObject unbindAll(String uid) throws DengluException {
		Request request = new Request(Verb.GET, getApiPath("all_unbind"));
		request.addQuerystringParameter("appid", appID);
		request.addQuerystringParameter("uid", uid);
		this.signRequest(request);
		String result = this.makeRequest(request);
		return (JSONObject) this.parseJson(result);
	}

	/**
	 * 发送登录的新鲜事
	 * 
	 * @param mediaUserID
	 *            从灯鹭获取的mediaUserID
	 * @throws DengluException
	 * @return 返回值 eg: {"result": "1"}
	 */
	public void sendLoginFeed(String mediaUserID) throws DengluException {
		Request request = new Request(Verb.GET, getApiPath("send_login_feed"));
		request.addQuerystringParameter("appid", appID);
		request.addQuerystringParameter("muid", mediaUserID);
		this.signRequest(request);
		this.makeRequest(request);
	}

	/**
	 * 用户发布帖子、日志等信息时，可以把此信息分享到第三方
	 * 
	 * @param mediaUserID
	 * @param content
	 *            分享显示的信息
	 * @param url
	 *            查看信息的链接
	 * @param uid
	 *            网站用户的唯一性标识ID
	 * @throws DengluException
	 * @return 返回值 eg: {"result": "1"}
	 */
	public void share(String mediaUserID, String content, String url, String uid) throws DengluException {
		Request request = new Request(Verb.GET, getApiPath("share"));
		request.addQuerystringParameter("appid", appID);
		request.addQuerystringParameter("muid", mediaUserID);
		request.addQuerystringParameter("uid", uid);
		request.addQuerystringParameter("content", content);
		request.addQuerystringParameter("url", url);
		this.signRequest(request);
		this.makeRequest(request);
	}

	/**
	 * 为HTTP请求加签名 签名算法： A、将请求参数格式化为“key=value”格式
	 * B、将上诉格式化好的参数键值对，以字典序升序排列后，拼接在一起；“key=valuekey=value”
	 * C、在上拼接好的字符串末尾追加上应用的api Key D、上述字符串的MD5值即为签名的值
	 * 
	 * @param request
	 */
	protected Request signRequest(Request request) {

		request.addQuerystringParameter("version", String.valueOf(version));
		request.addQuerystringParameter("timestamp", String.valueOf(System.currentTimeMillis()));
		request.addQuerystringParameter("sign_type", this.signatureMethod);

		Map<String, String> map = request.getQueryStringParams();
		StringBuffer parm = new StringBuffer("");
		for (String key : map.keySet()) {
			parm.append(key);
			parm.append("=");
			parm.append(map.get(key));
		}
		MessageDigest md = null;
		try {
			md = MessageDigest.getInstance("MD5");
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		byte[] digest = md.digest((parm.toString() + this.apiKey).getBytes());
		String sign = this.toHex(digest);
		request.addQuerystringParameter("sign", sign);
		return request;
	}

	private String toHex(byte[] buffer) {
		if (buffer != null) {
			StringBuffer sb = new StringBuffer(buffer.length * 2);
			for (int i = 0; i < buffer.length; i++) {
				sb.append(Character.forDigit((buffer[i] & 0xf0) >> 4, 16));
				sb.append(Character.forDigit(buffer[i] & 0x0f, 16));
			}
			return sb.toString();
		}
		return "";
	}

	/**
	 * 发送HTTP请求并获得响应
	 * 
	 * @param request
	 * @throws DengluException
	 */
	protected String makeRequest(Request request) throws DengluException {
		Response response = request.send();
		return response.getBody();
	}

	/**
	 * 从apiPath数组里获得相应method的实际调用地址
	 * 
	 * @param method
	 */
	protected String getApiPath(String method) {
		return apiPath.get(method);
	}

	/**
	 * 解析JSON字符串
	 * 
	 * 把从接口获取到的数据转换成json格式，在解析中进行接口返回错误分析
	 * 
	 * @param input
	 * @throws DengluException
	 */
	protected Object parseJson(String input) throws DengluException {
		if (null == input) {
			throw new DengluException("没有数据返回");
		}

		try {
			JSONTokener jsonTokener = new JSONTokener(input);
			Object o = jsonTokener.nextValue();
			if (o instanceof JSONObject) {
				JSONObject jsonObj = (JSONObject) o;
				if (jsonObj.has("errorCode")) {
					throw new DengluException(jsonObj.getString("errorDescription"), jsonObj.getInt("errorCode"));
				}
				return jsonObj;
			} else {
				JSONArray jsonArray = (JSONArray) o;
				return jsonArray;
			}
		} catch (Exception e) {
			if (e instanceof DengluException) {
				throw (DengluException) e;
			} else {
				throw new DengluException("解析json格式数据错误", e);
			}
		}
	}

	/**
	 * 
	 * @param input
	 */
	protected String urlEncode(String input) {
		try {
			return URLEncoder.encode(input, "UTF-8");
		} catch (UnsupportedEncodingException uee) {
			throw new IllegalStateException(String.format("Cannot find specified encoding: %s", "UTF-8"), uee);
		}
	}

	public String getApiKey() {
		return apiKey;
	}

	/**
	 * 
	 * @param newVal
	 */
	public void setApiKey(String newVal) {
		apiKey = newVal;
	}

	public String getAppID() {
		return appID;
	}

	/**
	 * 
	 * @param newVal
	 */
	public void setAppID(String newVal) {
		appID = newVal;
	}

	/**
	 * Provider的枚举，里面包括了/transfer/[name]的地址后缀
	 */
	public enum Provider {
		Google(Denglu.DENGLU_URL + "/transfer/google", Denglu.DENGLU_URL + "/transfer/google") {
			@Override
			public int getProviderId() {
				return 1;
			}

			@Override
			public String getProviderName() {
				return "Google";
			}
		},
		WindowsLive(Denglu.DENGLU_URL + "/transfer/windowslive", Denglu.DENGLU_URL + "/transfer/windowslive") {
			@Override
			public int getProviderId() {
				return 2;
			}

			@Override
			public String getProviderName() {
				return "Windows Live";
			}
		},
		Sina(Denglu.DENGLU_URL + "/transfer/sina", Denglu.DENGLU_URL + "/transfer/sina") {
			@Override
			public int getProviderId() {
				return 3;
			}

			@Override
			public String getProviderName() {
				return "新浪微博";
			}
		},
		Tencent(Denglu.DENGLU_URL + "/transfer/tencent", Denglu.DENGLU_URL + "/transfer/tencent") {
			@Override
			public int getProviderId() {
				return 4;
			}

			@Override
			public String getProviderName() {
				return "腾讯微博";
			}
		},
		Sohu(Denglu.DENGLU_URL + "/transfer/sohu", Denglu.DENGLU_URL + "/transfer/sohu") {
			@Override
			public int getProviderId() {
				return 5;
			}

			@Override
			public String getProviderName() {
				return "搜狐微博";
			}
		},
		Netease(Denglu.DENGLU_URL + "/transfer/netease", Denglu.DENGLU_URL + "/transfer/netease") {
			@Override
			public int getProviderId() {
				return 6;
			}

			@Override
			public String getProviderName() {
				return "网易微博";
			}
		},
		Renren(Denglu.DENGLU_URL + "/transfer/renren", Denglu.DENGLU_URL + "/transfer/renren") {
			@Override
			public int getProviderId() {
				return 7;
			}

			@Override
			public String getProviderName() {
				return "人人网";
			}
		},
		Kaixin001(Denglu.DENGLU_URL + "/transfer/kaixin001", Denglu.DENGLU_URL + "/transfer/kaixin001") {
			@Override
			public int getProviderId() {
				return 8;
			}

			@Override
			public String getProviderName() {
				return "开心网";
			}
		},
		Douban(Denglu.DENGLU_URL + "/transfer/douban", Denglu.DENGLU_URL + "/transfer/douban") {
			@Override
			public int getProviderId() {
				return 9;
			}

			@Override
			public String getProviderName() {
				return "豆瓣网";
			}
		},
		Yahoo(Denglu.DENGLU_URL + "/transfer/yahoo", Denglu.DENGLU_URL + "/transfer/yahoo") {
			@Override
			public int getProviderId() {
				return 12;
			}

			@Override
			public String getProviderName() {
				return "雅虎";
			}
		},
		QZone(Denglu.DENGLU_URL + "/transfer/qzone", Denglu.DENGLU_URL + "/transfer/qzone") {
			@Override
			public int getProviderId() {
				return 13;
			}

			@Override
			public String getProviderName() {
				return "QQ空间";
			}
		},
		Alipay(Denglu.DENGLU_URL + "/transfer/alipay", Denglu.DENGLU_URL + "/transfer/alipay") {
			@Override
			public int getProviderId() {
				return 15;
			}

			@Override
			public String getProviderName() {
				return "支付宝";
			}
		},
		Taobao(Denglu.DENGLU_URL + "/transfer/taobao", Denglu.DENGLU_URL + "/transfer/taobao") {
			@Override
			public int getProviderId() {
				return 16;
			}

			@Override
			public String getProviderName() {
				return "淘宝";
			}
		},
		Tianya(Denglu.DENGLU_URL + "/transfer/tianya", Denglu.DENGLU_URL + "/transfer/tianya") {
			@Override
			public int getProviderId() {
				return 17;
			}

			@Override
			public String getProviderName() {
				return "天涯";
			}
		},
		AlipayQuick(Denglu.DENGLU_URL + "/transfer/alipayquick", Denglu.DENGLU_URL + "/transfer/alipayquick") {
			@Override
			public int getProviderId() {
				return 18;
			}

			@Override
			public String getProviderName() {
				return "支付宝";
			}
		},
		Baidu(Denglu.DENGLU_URL + "/transfer/baidu", Denglu.DENGLU_URL + "/transfer/baidu") {
			@Override
			public int getProviderId() {
				return 19;
			}

			@Override
			public String getProviderName() {
				return "百度";
			}
		};
		private String authLoginUrl;
		private String authBindUrl;

		public String getAuthLoginUrl() {
			return authLoginUrl;
		}

		public void setAuthLoginUrl(String authLoginUrl) {
			this.authLoginUrl = authLoginUrl;
		}

		public String getAuthBindUrl() {
			return authBindUrl;
		}

		public void setAuthBindUrl(String authBindUrl) {
			this.authBindUrl = authBindUrl;
		}

		Provider(String authLoginUrl, String authBindUrl) {
			this.authLoginUrl = authLoginUrl;
			this.authBindUrl = authBindUrl;
		}

		public abstract String getProviderName();

		public abstract int getProviderId();

		public static Provider guess(String provider) {
			if (provider == null || provider.equals("")) {
				return null;
			}
			for (Provider p : Provider.values()) {
				if (p.name().toLowerCase().contains(provider.toLowerCase())) {
					return p;
				}
			}
			return null;
		}

		public static Provider get(int providerId) {
			for (Provider p : Provider.values()) {
				if (p.getProviderId() == providerId) {
					return p;
				}
			}
			return null;
		}
	}

	class Request {
		private final String url;
		private final Verb verb;
		private final Map<String, String> querystringParams;
		private HttpURLConnection connection;

		public Request(Verb verb, String url) {
			this.verb = verb;
			this.url = url;
			this.querystringParams = new TreeMap<String, String>();
		}

		public Response send() throws DengluException {
			try {
				createConnection();
				return doSend();
			} catch (DengluException ioe) {
				throw new DengluException("Problems while creating connection", ioe, ioe.geterrorCode());
			}
		}

		private void createConnection() throws DengluException {
			try {
				String effectiveUrl = appendParametersToQueryString(url, querystringParams);
				if (connection == null) {
					System.setProperty("http.keepAlive", "false");
					connection = (HttpURLConnection) new URL(effectiveUrl).openConnection();
				}
			} catch (Exception e) {
				throw new DengluException(e);
			}
		}

		private String appendParametersToQueryString(String url, Map<String, String> querystringParams) {
			if (null == querystringParams || querystringParams.size() == 0) {
				return url;
			}

			StringBuffer stringBuffer = new StringBuffer();
			for (String key : querystringParams.keySet()) {
				stringBuffer.append("&").append(key).append("=").append(querystringParams.get(key));
			}
			url += "?" + stringBuffer.toString().substring(1);
			return url;
		}

		Response doSend() throws DengluException {
			try {
				connection.setRequestMethod(this.verb.name());
				return new Response(connection);
			} catch (Exception e) {
				throw new DengluException(e);
			}
		}

		public void addQuerystringParameter(String key, String value) {
			this.querystringParams.put(key, value);
		}

		public Map<String, String> getQueryStringParams() {
			return this.querystringParams;
		}

		public String getUrl() {
			return url;
		}

		public Verb getVerb() {
			return verb;
		}

		@Override
		public String toString() {
			return String.format("@Request(%s %s)", getVerb(), getUrl());
		}
	}

	class Response {
		private static final String EMPTY = "";

		private int code;
		private String body;
		private InputStream stream;
		private Map<String, String> headers;

		Response(HttpURLConnection connection) throws DengluException {
			try {
				connection.connect();
				code = connection.getResponseCode();
				headers = parseHeaders(connection);
				stream = wasSuccessful() ? connection.getInputStream() : connection.getErrorStream();
			} catch (UnknownHostException e) {
				code = 404;
				body = EMPTY;
			} catch (IOException e) {
				throw new DengluException(e);
			}
		}

		private String parseBodyContents() throws DengluException {
			try {
				InputStream is = getStream();
				final char[] buffer = new char[0x10000];
				StringBuilder out = new StringBuilder();
				Reader in = new InputStreamReader(is, "UTF-8");
				int read;
				do {
					read = in.read(buffer, 0, buffer.length);
					if (read > 0) {
						out.append(buffer, 0, read);
					}
				} while (read >= 0);
				in.close();
				body = out.toString();
			} catch (IOException ioe) {
				throw new DengluException("Error while reading response body", ioe);
			}
			return body;
		}

		private Map<String, String> parseHeaders(HttpURLConnection conn) {
			Map<String, String> headers = new TreeMap<String, String>();
			Set<String> headerSet = conn.getHeaderFields().keySet();
			if (null == headers || headers.isEmpty()) {
				return headers;
			}
			for (String key : headerSet) {
				List<String> value = conn.getHeaderFields().get(key);
				if (null == value || value.isEmpty()) {
					continue;
				}
				headers.put(key, value.get(0));
			}
			return headers;
		}

		private boolean wasSuccessful() {
			return getCode() >= 200 && getCode() < 400;
		}

		public String getBody() throws DengluException {
			return body != null ? body : parseBodyContents();
		}

		public InputStream getStream() {
			return stream;
		}

		public int getCode() {
			return code;
		}

		public Map<String, String> getHeaders() {
			return headers;
		}

		public String getHeader(String name) {
			return headers.get(name);
		}

	}

	enum Verb {
		GET, POST, PUT, DELETE
	}
}

class BASE64Encoder {
	private static final char last2byte = (char) Integer.parseInt("00000011", 2);
	private static final char last4byte = (char) Integer.parseInt("00001111", 2);
	private static final char last6byte = (char) Integer.parseInt("00111111", 2);
	private static final char lead6byte = (char) Integer.parseInt("11111100", 2);
	private static final char lead4byte = (char) Integer.parseInt("11110000", 2);
	private static final char lead2byte = (char) Integer.parseInt("11000000", 2);
	private static final char[] encodeTable = new char[] { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b',
		'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' };

	public BASE64Encoder() {
	}

	public String encode(byte[] from) {
		StringBuffer to = new StringBuffer((int) (from.length * 1.34) + 3);
		int num = 0;
		char currentByte = 0;
		for (int i = 0; i < from.length; i++) {
			num = num % 8;
			while (num < 8) {
				switch (num) {
				case 0:
					currentByte = (char) (from[i] & lead6byte);
					currentByte = (char) (currentByte >>> 2);
					break;
				case 2:
					currentByte = (char) (from[i] & last6byte);
					break;
				case 4:
					currentByte = (char) (from[i] & last4byte);
					currentByte = (char) (currentByte << 2);
					if ((i + 1) < from.length) {
						currentByte |= (from[i + 1] & lead2byte) >>> 6;
					}
					break;
				case 6:
					currentByte = (char) (from[i] & last2byte);
					currentByte = (char) (currentByte << 4);
					if ((i + 1) < from.length) {
						currentByte |= (from[i + 1] & lead4byte) >>> 4;
					}
					break;
				}
				to.append(encodeTable[currentByte]);
				num += 6;
			}
		}
		if (to.length() % 4 != 0) {
			for (int i = 4 - to.length() % 4; i > 0; i--) {
				to.append("=");
			}
		}
		return to.toString();
	}
}